7. Cache Configuration

Caches referenced by the annotations can be configured, either in an ehcache.xml (usually kept in the grails-app/conf directory) file, using EhCacheFactoryBean definitions in grails-app/conf/spring/resources.groovy or via Config.groovy. If you do not configure caches individually they will be created on demand using defaults.

Configuring caches with resources.groovy

You can configure caches in grails-app/conf/spring/resources.groovy using instances of Spring's EhCacheFactoryBean class. For example:

grails-app/conf/spring/resources.groovy

pirateCache(EhCacheFactoryBean) { bean ->
    cacheManager = ref("springcacheCacheManager")
    cacheName = "pirateCache"
    // these are just examples of properties you could set
    eternal = false
    diskPersistent = false
    memoryStoreEvictionPolicy = "LRU"
}

You can inherit default cache properties from those defined in Config.groovy by setting the factory bean's parent to 'springcacheDefaultCache'. For example:

pirateCache(EhCacheFactoryBean) { bean ->
    bean.parent = ref("springcacheDefaultCache")
    cacheName = "pirateCache"
    // set any properties unique to this cache
    memoryStoreEvictionPolicy = "LRU"
}

Configuring caches with Config.groovy

The Springcache plugin enables you to define caches in Config.groovy for convenience. For example:

grails-app/conf/Config.groovy

springcache {
    defaults {
        // set default cache properties that will apply to all caches that do not override them
        eternal = false
        diskPersistent = false
    }
    caches {
        pirateCache {
            // set any properties unique to this cache
            memoryStoreEvictionPolicy = "LRU"
        }
    }
}

Under the hood this is simply setting up EhCacheFactoryBean instances in the Spring context, so it is up to you whether you prefer to use resources.groovy or Config.groovy there is not much difference.

The properties shown are just examples, see the EhCacheFactoryBean documentation for full details of all the properties you can set.

8.1. Tips

Flushing content caches with service methods and vice-versa

There is nothing special about the different types of cache so it's perfectly fine to flush a content cache with a @CacheFlush annotation on a service method or a service method cache with a @CacheFlush annotation on a controller action. There's also no reason that you shouldn't use the same cache for both service method and content caching the keys will be quite distinct so this will not be a problem.

Tearing down caches in tests

In integration test and some types of functional test (e.g. Selenium RC tests when not running in remote mode) your tests can have Spring beans automatically injected. You can use this facility to tear down caches between tests. For example:

def springcacheService // auto-injected service bean from plugin

void tearDown() { super.tearDown() springcacheService.flushAll() // only need to do this if your tests are making assertions about hit/miss counts, etc. springcacheService.clearStatistics() }

Disabling

Rather than tearing down caches between tests you may prefer to disable the plugin altogether. This is done by setting the config key springcache.enabled = false which can be done on a per-environment basis. For example:

springcache {
    // cache definitions, etc
}

environments { development { springcache.enabled = false } }

Whilst this makes things simpler I would encourage you to run end-to-end tests and continuous integration in as 'production-like' an environment as possible. If your continuous integration build is running with the plugin enabled you are much less likely to get any surprising behaviour when you release your app to a production environment.

Logging

To see logging from the plugin set the logging level on grails.plugin.springcache in your Config.groovy file.

Response headers

The plugin sets a header X-Springcache-Cached with a value of true or false to indicate whether or not a controller response was served from the cache. This only applies to the "main" request and not to any content included using the g:include tag.

8.2. FAQ

Can I evict only some of the contents of a cache instead of flushing the whole thing?

No. It's not possible to 'reverse engineer' cache keys into the values that were used to generate them so how would you know which keys to evict? If you find yourself asking this question you should consider using more focused caches rather than putting everything into the same bucket. The pursuit of 100% efficiency where no service method or controller action is ever invoked when its contents could conceivably have been served from a cache is subject to the law of diminishing returns. Any time you flush a cache you may well discard some entries that could potentially still have been used but so long as your caches are set up sensibly that's really not something that you should worry about.

My cache config doesn't seem to be working.

Ensure all your config for the Springcache plugin is nested inside a single springcache block in Config.groovy otherwise only the last block will take effect.

Can I programatically disable caching in specific circumstances such as when a user is logged in?

In the case of controller caching you can do so by setting a Cache-Control response header with a value of "no-cache" which can be done manually, or by using the command cache false provided by the Cache Headers plugin. See Cache Headers

Why isn't there a taglib so I can just wrap parts of my page that need caching?

It's something I may add but from a purist point of view I'm not very keen on the idea. Caching is a separate concern from view rendering and the two really shouldn't be mixed up. So far the plugin has deliberately taken a declarative approach to caching which encourages you to maintain a good separation of concerns.

If this is something you really want to see, vote for the issue on JIRA here: "GRAILSPLUGINS-2564":http://jira.codehaus.org/browse/GRAILSPLUGINS-2564

8.3. Upgrading From Earlier Versions

Successive versions of the plugin have introduced some non-backwards compatible changes. If you are upgrading from an earlier version you will need to consider the following:

Upgrading from 1.2.* to 1.3:

Upgrading from 1.1.* to 1.2:

From pre 1.1: